package com.share.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.AsyncRabbitTemplate;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import java.util.HashMap;
import java.util.Map;

/**
 * @desc:
 * @author:caifan
 * @date:2020/3/31
 */
@Configuration
public class RabbitmqConfig {

    @Value("${spring.rabbitmq.host}")
    private String host;

    @Value("${spring.rabbitmq.virtual-host}")
    private String virtualHost;

    @Value("${spring.rabbitmq.username}")
    private String username;

    @Value("${spring.rabbitmq.password}")
    private String password;

    @Value("${spring.rabbitmq.port}")
    private Integer port;

    /**
     * 创建连接工厂
     * @return
     */
    @Bean
    public ConnectionFactory connectionFactory () {
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
        cachingConnectionFactory.setHost(host);
        cachingConnectionFactory.setVirtualHost(virtualHost);
        cachingConnectionFactory.setPort(port);
        cachingConnectionFactory.setUsername(username);
        cachingConnectionFactory.setPassword(password);
        cachingConnectionFactory.setConnectionTimeout(100000);
        cachingConnectionFactory.setCloseTimeout(100000);
        return cachingConnectionFactory;
    }

    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    @Bean
    public AsyncRabbitTemplate asyncRabbitTemplate(RabbitTemplate rabbitTemplate, ConnectionFactory connectionFactory) {
        /*SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);
        simpleMessageListenerContainer.setConcurrentConsumers(20);
        simpleMessageListenerContainer.setReceiveTimeout(60000);
        simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);
        simpleMessageListenerContainer.setQueueNames("bootQueue2", "bootQueue3");
        AsyncRabbitTemplate asyncRabbitTemplate = new AsyncRabbitTemplate(rabbitTemplate, simpleMessageListenerContainer);*/
        AsyncRabbitTemplate asyncRabbitTemplate = new AsyncRabbitTemplate(rabbitTemplate);
        asyncRabbitTemplate.setAutoStartup(true);
        asyncRabbitTemplate.setReceiveTimeout(60000);
        asyncRabbitTemplate.setEnableConfirms(true);
        return asyncRabbitTemplate;
    }

    @Bean
    public DirectExchange deadExchange() {
        return new DirectExchange("deadExchange", true, false);
    }

    @Bean
    public DirectExchange directExchange() {
        DirectExchange directExchange = new DirectExchange("share.boot.directExchange");
        return directExchange;
    }

    @Bean
    public TopicExchange topicExchange() {
        TopicExchange topicExchange = new TopicExchange("share.boot.topicExchange");

        return topicExchange;
    }

    @Bean
    public FanoutExchange fanoutExchange() {
        FanoutExchange fanoutExchange = new FanoutExchange("share.boot.fanoutExchange");

        return fanoutExchange;
    }

    /**
     * 延时队列，rabbitmq服务端需要安装插件
     * @return
     */
    @Bean
    public CustomExchange customExchange() {
        Map<String, Object> map = new HashMap<>();
        map.put("x-delayed-type", "direct");
        return new CustomExchange("share.delayExchange", "x-delayed-message", true, false, map);
    }

    @Bean
    public Queue deadQueue() {
        return new Queue("deadQueue", true, false, false);
    }

    /**
     * 死信条件
     * 1.超过队列长度
     * 2.拒绝消费
     * 3.过期
     * @return
     */
    @Bean
    public Queue directQueue() {
        // 设置参数
        Map<String, Object> args = new HashMap<>();
        // 死信队列参数
        args.put("x-dead-letter-exchange", "deadExchange");
        args.put("x-dead-letter-routing-key", "deadRouting");
        // 设置队列最大长度
        args.put("x-max-length", 5);
        return new Queue("share.directQueue", true, false, false, args);
    }

    @Bean
    public Queue topicQueue() {
        return new Queue("share.topicQueue", true, false, false);
    }

    @Bean
    public Queue fanoutQueue() {
        return new Queue("share.fanoutQueue", true, false, false);
    }

    @Bean
    public Queue delayQueue() {
        return new Queue("share.delayQueue", true, false, false);
    }

    @Bean
    public Binding deadBinder() {
        return BindingBuilder.bind(deadQueue()).to(deadExchange()).with("deadRouting");
    }

    @Bean
    public Binding directBinder() {
        return BindingBuilder.bind(directQueue()).to(directExchange()).with("springboot.key");
    }

    @Bean
    public Binding topicBinder() {
        return BindingBuilder.bind(topicQueue()).to(topicExchange()).with("springboot.topic");
    }

    @Bean
    public Binding fanoutBinder() {
        return BindingBuilder.bind(fanoutQueue()).to(fanoutExchange());
    }

    @Bean
    public Binding delayBinder() {
        return BindingBuilder.bind(delayQueue()).to(customExchange()).with("delay.key").noargs();
    }

    @Bean
    public DirectExchange asynDirectExchange() {
        return new DirectExchange("springboot.direct.exchange", true, false);
    }

    @Bean
    public Queue asyncQueue() {
        return new Queue("bootQueue4", true, false, false);
    }

    @Bean
    public Binding asynBinder() {
        return BindingBuilder.bind(asyncQueue()).to(asynDirectExchange()).with("springboot.key4");
    }
}

